using System;
using System.Diagnostics;
using System.ComponentModel;
using ZoneFiveSoftware.Common.Data;
using ZoneFiveSoftware.Common.Data.Fitness;
using FilteredStatistics.Common;
using FilteredStatistics.Controller;

namespace FilteredStatistics.Data
{
    class STZonesNamedZone : INamedZone
    {
        public STZonesNamedZone(STZonesFilterCriteria parent, IActivity activity, INamedLowHighZone STNamedZone)
        {
            m_ParentList = parent;
            m_STNamedZone = STNamedZone;

            m_ParentList.ZoneCategory.PropertyChanged += new PropertyChangedEventHandler(OnZoneCategoryPropertyChanged);

            m_ActivityCallbackHelper = new ActivityDataChangedHelper(m_ParentList.GetActivity());
            m_ActivityCallbackHelper.PropertyChanged += new PropertyChangedEventHandler(OnActivityDataChanged);

            Activity = activity;

            m_CachedInfoDirty = true;
        }

        void OnZoneCategoryPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Zones")
            {
                if (m_ParentList.ZoneCategory.Zones.Contains(STNamedZone))
                {
                    m_CachedInfoDirty = true;

                    TriggerValidTimesChanged();
                }
            }
        }

#region INamedZone Members

        public String Name
        {
            get { return STNamedZone.Name; }
        }

        public IValueRangeSeries<DateTime> ValidTimes
        {
            get
            {
                RefreshCachedZoneInfo();

                if (m_CachedZoneInfo != null)
                {
                    return m_CachedZoneInfo.Times;
                }
                else
                {
                    return (ValueRangeSeries<DateTime>)WholeActivityFilteredDataSet.Instance.GetFilteredTimes();
                }
            }
        }

        public event PropertyChangedEventHandler ValidTimesChanged;

#endregion

        void OnActivityDataChanged(object sender, PropertyChangedEventArgs e)
        {
            bool dataChanged = false;

            if (e.PropertyName == "Activity.Duration")
            {
                dataChanged = true;
            }
            else if (e.PropertyName == "Activity.CadencePerMinuteTrack")
            {
                if (PluginMain.GetApplication().Logbook.CadenceZones.Contains(m_ParentList.ZoneCategory))
                {
                    dataChanged = true;
                }
            }
            else if (e.PropertyName == "Activity.HeartRatePerMinuteTrack")
            {
                if (PluginMain.GetApplication().Logbook.HeartRateZones.Contains(m_ParentList.ZoneCategory))
                {
                    dataChanged = true;
                }
            }
            else if (e.PropertyName == "Activity.PowerWattsTrack")
            {
                if (PluginMain.GetApplication().Logbook.PowerZones.Contains(m_ParentList.ZoneCategory))
                {
                    dataChanged = true;
                }
            }

            if(dataChanged)
            {
                m_CachedInfoDirty = true;
                TriggerValidTimesChanged();
            }
        }

        protected void TriggerValidTimesChanged()
        {
            if (ValidTimesChanged != null)
            {
                ValidTimesChanged(this, new PropertyChangedEventArgs("ValidTimes"));
            }
        }

        private void RefreshCachedZoneInfo()
        {
            if (m_CachedInfoDirty)
            {
                m_CachedZoneInfo = null;

                if (Activity != null)
                {
                    INumericTimeDataSeries dataTrack = GetCorrespondingDataTrack(Activity, m_ParentList.STZoneType);

                    if (dataTrack != null && dataTrack.Count > 0)
                    {
                        ActivityInfo activityInfo = ActivityInfoCache.Instance.GetInfo(Activity);
                        ZoneCategoryInfo categoryInfo = ZoneCategoryInfo.Calculate(activityInfo, m_ParentList.ZoneCategory, dataTrack, 1.0f);

                        foreach (ZoneInfo zoneInfo in categoryInfo.Zones)
                        {
                            if (zoneInfo.Zone == STNamedZone)
                            {
                                m_CachedZoneInfo = zoneInfo;
                                break;
                            }
                        }

                        Debug.Assert(m_CachedZoneInfo != null);
                    }
                }

                m_CachedInfoDirty = false;
            }
        }

        private INumericTimeDataSeries GetCorrespondingDataTrack(IActivity activity, STZonesFilterCriteria.STZoneTypes type)
        {
            Debug.Assert(activity != null);
            ActivityInfo activityCache = ActivityInfoCache.Instance.GetInfo(activity);
            Debug.Assert(activityCache != null);
            INumericTimeDataSeries actualTrack;

            switch (type)
            {
                case STZonesFilterCriteria.STZoneTypes.Cadence:
                    {
                        actualTrack = activityCache.SmoothedCadenceTrack;
                        break;
                    }
                case STZonesFilterCriteria.STZoneTypes.Climb:
                    {
                        actualTrack = new NumericTimeDataSeries();

                        INumericTimeDataSeries tempResult = activityCache.SmoothedGradeTrack;

                        // Remap to gradient in percent ( * 100)
                        foreach (ITimeValueEntry<float> currentGrade in tempResult)
                        {
                            actualTrack.Add(tempResult.EntryDateTime(currentGrade), currentGrade.Value * 100.0f);
                        }
                        break;
                    }
                case STZonesFilterCriteria.STZoneTypes.HeartRate:
                    {
                        actualTrack = activityCache.SmoothedHeartRateTrack;
                        break;
                    }
                case STZonesFilterCriteria.STZoneTypes.Speed:
                    {
                        actualTrack = activityCache.SmoothedSpeedTrack;
                        break;
                    }
                case STZonesFilterCriteria.STZoneTypes.Power:
                    {
                        actualTrack = activityCache.SmoothedPowerTrack;
                        break;
                    }
                default:
                    {
                        Debug.Assert(false);

                        return null;
                    }
            }

            return actualTrack;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            STZonesNamedZone namedZone = obj as STZonesNamedZone;

            if (namedZone != null)
            {
                return namedZone.STNamedZone == STNamedZone;
            }

            return base.Equals(obj);
        }

        public IActivity Activity
        {
            get
            {
                if (m_ParentList != null)
                {
                    return m_ParentList.GetActivity();
                }

                return null;
            }
            set
            {
                m_ActivityCallbackHelper.Activity = value;

                m_CachedInfoDirty = true;
                TriggerValidTimesChanged();
            }
        }

        public INamedLowHighZone STNamedZone
        {
            get { return m_STNamedZone; }
        }

        private ActivityDataChangedHelper m_ActivityCallbackHelper = null;
        private STZonesFilterCriteria m_ParentList = null;
        private INamedLowHighZone m_STNamedZone;
        private ZoneInfo m_CachedZoneInfo;
        private bool m_CachedInfoDirty = false;
    }
}
